package de.bht.esa.weather.usermanager;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

/**
 *
 * @author Andreas Goese
 * @author Sven Höche
 * 
 * Diese Klasse representiert die Benutzerverwaltung. Sie dient zum persistieren
 * des FrontendUsers, zur Verwaltung und zum abrufen der Datenbankeinträge.
 * 
 */

@Stateless
@LocalBean
public class UserManager {

    private EntityManager em;

    @PostConstruct
    private void initEntityManager() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("FrontendUserPU");
        this.em = emf.createEntityManager();
    }
    
     /**
     * Gibt einen Benutzer anhand der ID zurück.
     * 
     * @param id BenutzerID des zu suchenden Benutzers
     * @return 
     */
    public FrontendUser getUser(long id) {
        return em.find(FrontendUser.class, id);
    }
    
    /**
     * Gibt einen Benutzer anhand des Namens zurück.
     * 
     * @param name Benutzername des zu suchenden Benutzers
     * @return 
     */
    public FrontendUser getOneUser(String name){
        final CriteriaBuilder cb = em.getCriteriaBuilder();
        final CriteriaQuery<FrontendUser> query = cb.createQuery(FrontendUser.class);
        final Root<FrontendUser> root = query.from(FrontendUser.class);

        if (name != null && name.length() > 0) {
            final Predicate condition = cb.like(root.<String>get("name"), name);
            query.where(condition);
        }
        try{
            return em.createQuery(query).getSingleResult();
        }catch(NoResultException ex){
            return null;
        }
    }

    /**
     * Gibt eine Liste von Benutzern zurück, anhand einer teilweisen Namensangabe.
     * @param name Benutzername oder teilweiser Benutzername des zu suchenden Benutzers
     * @return 
     */
    public List<FrontendUser> getUsers(String name) {
        final CriteriaBuilder cb = em.getCriteriaBuilder();
        final CriteriaQuery<FrontendUser> query = cb.createQuery(FrontendUser.class);
        final Root<FrontendUser> root = query.from(FrontendUser.class);

        if (name != null && name.length() > 0) {
            final Predicate condition = cb.like(root.<String>get("name"), "%" + name + "%");
            query.where(condition);
        }
        return em.createQuery(query).getResultList();
    }

    /**
     * Gibt eine Liste von Benutzern zurück, anhand einer Benutzerrolle.
     * @param role Benutzerrolle der zu suchenden Benutzer
     * @return 
     */
    public List<FrontendUser> findUserByRole(String role) {
        final CriteriaBuilder cb = em.getCriteriaBuilder();
        final CriteriaQuery<FrontendUser> query = cb.createQuery(FrontendUser.class);
        final Root<FrontendUser> root = query.from(FrontendUser.class);

        if (role != null && role.length() > 0) {
            final Predicate condition = cb.like(root.<String>get("userRole"), role);
            query.where(condition);
        }
        return em.createQuery(query).getResultList();
    }

    /**
     * Speichert einen Benutzer innerhalb der Datenbank.
     * @param u zu speicherndes Benutzerobjekt
     */
    public void saveUser(FrontendUser u) {
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        em.merge(u);
        tx.commit();
    }

    /**
     * Entfernt einen Benutzer aus der Datenbank.
     * @param u zu entfernendes Benutzerobjekt
     */
    public void removeUser(FrontendUser u) {
        EntityTransaction tx = em.getTransaction();
        
        if(u.getUserRole().equals("USER")){
            tx.begin();
            em.remove(u);
            tx.commit();
        }
        
        if(u.getUserRole().equals("ADMIN")){
            List<FrontendUser> frontendAdminRoleList = findUserByRole("ADMIN");
            if (frontendAdminRoleList.size() > 1) {
                tx.begin();
                em.remove(u);
                tx.commit();
            }else {
                throw new IllegalStateException("You cant remove the last admin user");
            }
        }
    }
}
